/*
*    Qizx/open 3.0 beta
*
* This code is the open-source version of Qizx.
* Copyright (C) 2004-2009 Axyana Software -- All rights reserved.
*
* The contents of this file are subject to the Mozilla Public License 
*  Version 1.1 (the "License"); you may not use this file except in 
*  compliance with the License. You may obtain a copy of the License at
*  http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
*  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
*  for the specific language governing rights and limitations under the
*  License.
*
* The Initial Developer of the Original Code is Xavier Franc - Axyana Software.
*
*/
using System;
using EvaluationException = System.Qizx.Api.EvaluationException;
using QName = System.Qizx.Api.QName;
using System.Qizx.XQuery;
using SingleItem = System.Qizx.XQuery.Dt.SingleItem;
namespace System.Qizx.XQuery.Op
{
	
	/// <summary> class VarReference: replaced by VarReference.Global or VarReference.Local</summary>
	public class VarReference:LeafExpression
	{
		public QName name;
		
		public VarReference(QName name)
		{
			this.name = name;
		}
		
		public override void  Dump(ExprDisplay d)
		{
			d.header("var");
			d.property("name", name);
		}
		
		public override Expression StaticCheck(ModuleContext context, int flags)
		{
			// is it a local ?
			LocalVariable decl = context.lookforLocalVariable(name);
			if (decl != null)
				return new Local(decl).atSamePlaceAs(this);
			// is it a global ?
			GlobalVariable global = context.lookforGlobalVariable(name);
			if (global != null)
				return new Global(global).atSamePlaceAs(this);
			
			context.error("XPST0008", this, "variable " + context.PrefixedName(name) + " not declared");
			return this;
		}
		
		internal class Global:VarReference
		{
			public override int Flags
			{
				get
				{
					return address.Flags;
					// // if single Node: necessarily at same_depth!
					// return Type.isRepeatable(type.getOccurrence()) ?
					// 0 : (DOCUMENT_ORDER + SAME_DEPTH);
				}
				
			}
			internal GlobalVariable address;
			
			internal Global(GlobalVariable address):base(address.name)
			{
				this.address = address;
				this.type = address.getType();
			}
			
			public  override bool Equals(System.Object obj)
			{
				if (obj is Global)
				{
					return address.name.Equals(((Global) obj).address.name);
				}
				return false;
			}
			
			public override int GetHashCode()
			{
				return address.name.GetHashCode();
			}
			
			public override void  Dump(ExprDisplay d)
			{
				d.header("global");
				d.property("name", address.name);
				d.property("declaredType", address.declaredType);
				d.headerInfo(this);
			}
			
			public override XQValue eval(Focus focus, EvalContext context)
			{
				return context.loadGlobal(address);
			}
		}
		
		public class Local:VarReference
		{
			public override int Flags
			{
				get
				{
					// if single Node: necessarily at same_depth!
					return XQType.isRepeatable(type.Occurrence)?0:(DOCUMENT_ORDER + SAME_DEPTH);
				}
				
			}
			
			public LocalVariable decl;
			
			internal Local(LocalVariable decl):base(decl.name)
			{
				this.decl = decl;
				type = decl.type;
				decl.use();
			}
			
			internal Local(QName name):base(name)
			{
			}
			
			public  override bool Equals(System.Object obj)
			{
				if (obj is Local)
				{
					return decl.Equals(((Local) obj).decl);
				}
				return false;
			}
			
			public override int GetHashCode()
			{
				return decl.GetHashCode();
			}
			
			public override void  Dump(ExprDisplay d)
			{
				d.header("local");
				d.property("name", name);
				//d.property("uses", decl.uses);
				if (decl != null)
					d.property("address", decl.address);
				d.headerInfo(this);
			}
			
			public override XQValue eval(Focus focus, EvalContext context)
			{
				// special meaning: a flower var replaced by . in predicates
				if (decl == null)
				{
					checkFocus(focus, context);
					return new SingleItem(focus.currentItem());
				}
				return context.loadLocal(decl.address);
			}
			
			public override XQItem evalAsItem(Focus focus, EvalContext context)
			{
				// special meaning: a flower var replaced by . in predicates
				if (decl == null)
					return focus.currentItem();
				return context.loadLocalItem(decl.address);
			}
			
			public override XQItem evalAsOptItem(Focus focus, EvalContext context)
			{
				if (decl == null)
					return focus.currentItem();
				return context.loadLocalItem(decl.address);
			}
			
			public override long evalAsInteger(Focus focus, EvalContext context)
			{
				if (decl == null)
					return focus.currentItemAsInteger();
				return context.loadLocalInteger(decl.address);
			}
			
			public override long evalAsOptInteger(Focus focus, EvalContext context)
			{
				if (decl == null)
					return focus.currentItemAsInteger();
				return context.loadLocalInteger(decl.address);
			}
			
			public override double evalAsDouble(Focus focus, EvalContext context)
			{
				if (decl == null)
					return focus.currentItemAsDouble();
				return context.loadLocalDouble(decl.address);
			}
			
			public override double evalAsOptDouble(Focus focus, EvalContext context)
			{
				if (decl == null)
					return focus.currentItemAsDouble();
				return context.loadLocalDouble(decl.address);
			}
			
			public override string evalAsString(Focus focus, EvalContext context)
			{
				if (decl == null)
					return focus.currentItemAsString();
				return context.loadLocalString(decl.address);
			}
			
			public override string evalAsOptString(Focus focus, EvalContext context)
			{
				if (decl == null)
					return focus.currentItemAsString();
				return context.loadLocalString(decl.address);
			}
		}
	}
}